/* 多进程-TCP 服务端 */

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <string.h>
#include <sys/wait.h>    //for wait()

using namespace std;

#define Judge(ret){if(ret < 0) {return 0;}}    //宏函数判断


/* 自定义信号处理函数-避免僵尸进程
 * */
void sigcallback(int signum)
{
    wait(NULL);
}

int main()
{
    signal(SIGCHLD, sigcallback);    //改变信号处理方式

    int listen_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    //Judge(listen_sockfd);
    if(listen_sockfd < 0)
    {
        perror("socket");
        return 0;
    }

    struct sockaddr_in ser_addr;
    ser_addr.sin_family = AF_INET;
    ser_addr.sin_port = htons(38989);
    ser_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
    int ret = bind(listen_sockfd, (struct sockaddr*)&ser_addr, sizeof(ser_addr));
    //Judge(ret);
    if(ret < 0)
    {
        perror("bind");
        return 0;
    }

    ret = listen(listen_sockfd, 5);
    //Judge(ret);  
    if(ret < 0)
    {
        perror("listen");
        return 0;
    }

    /*
     * 循环accept已连接套接字
     * */
    while(1)
    {
        struct sockaddr_in cli_addr;
        socklen_t cli_addr_len = sizeof(cli_addr);
        int new_sockfd = accept(listen_sockfd, (struct sockaddr*)&cli_addr, &cli_addr_len);
        if(new_sockfd < 0)
        {
            continue;
        }

        /* 多进程处理accept执行到的新套接字
         * */
        pid_t pid = fork();
        if(pid < 0)    //子进程创建失败
        {
            close(new_sockfd);    //关闭当前套接字
            continue;    //进行下一轮accept
        }
        else if(pid == 0)    //子进程
        {
            /* 子进程循环执行收发
             * */
            close(listen_sockfd);    //关闭（子进程的）侦听套接字

            while(1)
            {
                char buf[1024] = {0};
                ssize_t recv_size = recv(new_sockfd, buf, sizeof(buf) - 1, 0);    //收数据
                if(recv_size < 0)
                {
                    perror("recv");
                    continue;
                }
                else if(recv_size == 0)    //对端关闭
                {
                    //cout << "peer shutdown!" << endl;
                    printf("client[%s:%d] shutdown!\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
                    close(new_sockfd);
                    exit(1);
                }
                printf("server <- client[%s:%d]:%s\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port), buf);

                memset(buf, '\0', sizeof(buf));
                sprintf(buf,"client <- server[%s:%d]:Get!\n", inet_ntoa(ser_addr.sin_addr), ntohs(ser_addr.sin_port));
                send(new_sockfd, buf, strlen(buf), 0);    //发数据
            }
        }
        else    //父进程
        {
            // 关闭已被子进程获取的套接字，准备下一次accept
            close(new_sockfd);
        }
    }
    return 0;
}
